#include "catalog/column.h"

#include <sstream>
#include <string>

#include "common/logger.h"
#include "type/type.h"

const static Json::StaticString COLUMN_NAME("column_name");
const static Json::StaticString COLUMN_TYPE("column_type");
const static Json::StaticString COLUMN_FIXED_LENGTH("column_fixed_length");
const static Json::StaticString COLUMN_VAR_LENGTH("column_var_length");
const static Json::StaticString COLUMN_OFFSET("column_offset");

std::string Column::ToString() const {
    std::ostringstream os;

    os << "Column[" << column_name_ << ", " << Type::TypeIdToString(column_type_) << ", "
       << "Offset:" << column_offset_ << ", ";

    if (IsInlined()) {
        os << "FixedLength:" << fixed_length_;
    } else {
        os << "VarLength:" << variable_length_;
    }
    os << "]";
    return (os.str());
}

void Column::to_json(Json::Value &json_value) const {
    json_value[COLUMN_NAME] = column_name_;
    json_value[COLUMN_TYPE] = column_type_;
    json_value[COLUMN_FIXED_LENGTH] = fixed_length_;
    json_value[COLUMN_VAR_LENGTH] = variable_length_;
    json_value[COLUMN_OFFSET] = column_offset_;
}

bool Column::from_json(const Json::Value &json_value, Column &column) {
    if (!json_value.isObject()) {
        LOG_ERROR("Failed to deserialize field. json is not an object. json value=%s",
                  json_value.toStyledString().c_str());
    }
    const Json::Value &column_value = json_value[COLUMN_NAME];
    const Json::Value &column_type = json_value[COLUMN_TYPE];
    const Json::Value &fixed_length = json_value[COLUMN_FIXED_LENGTH];
    const Json::Value &variable_length = json_value[COLUMN_VAR_LENGTH];
    const Json::Value &column_offset = json_value[COLUMN_OFFSET];

    std::string column_name_json = column_value.asString();
    TypeId column_type_json = (TypeId)column_type.asInt();
    uint32_t fixed_length_json = (uint32_t)fixed_length.asUInt();
    uint32_t variable_length_json = (uint32_t)variable_length.asUInt();
    uint32_t column_offset_json = (uint32_t)column_offset.asUInt();
    if (column_type_json != TypeId::VARCHAR) {
        column.init(column_name_json, column_type_json, column_offset_json);
    } else {
        column.init(column_name_json, column_type_json, variable_length_json, column_offset_json);
    }
    return true;
}

void Column::init(std::string column_name, TypeId type, uint32_t offset) {
    DATABASE_ASSERT(type != TypeId::VARCHAR, "Wrong constructor for VARCHAR type.");
    column_name_ = column_name;
    column_type_ = type;
    fixed_length_ = TypeSize(type);
    column_offset_ = offset;
}
void Column::init(std::string column_name, TypeId type, uint32_t length, uint32_t offset) {
    DATABASE_ASSERT(type == TypeId::VARCHAR, "Wrong constructor for non-VARCHAR type.");
    column_name_ = column_name;
    column_type_ = type;
    fixed_length_ = (TypeSize(type));
    variable_length_ = length;
    column_offset_ = offset;
}